package main

import (
	"fmt"
	"reflect"
)

/*===通过反射设置变量的值===
  - elem 表示具体类型，需通过elem设置值
	- reflect.ValeuOf()返回的是Value类型，Value中保存原来结构体值的拷贝，修改会发生panic，需要调用reflect.ValueOf().Elem()获取原来结构体类型
		- Elem()方法内部将，reflect 下的rtype类型转换为runtime包下的类型，是对原始类型的修改，所以生效
*/
func main() {
	var a int64 = 100
	//setValue1(&a)//panic: reflect: reflect.Value.SetInt using unaddressable value
	setValue2(&a)
	fmt.Println("after update: a = ", a)
}

//修改的是copy到堆上的值副本(值拷贝)，这个副本只是临时拷贝，返回后地址不可用，会引发panic。对原始地址的值未修改。
func setValue1(x interface{}) {
	/* [01] 获取 Value 对象，返回的是Value.ptr是指向a的拷贝后的地址 */
	value := reflect.ValueOf(x)
	if value.Kind() == reflect.Int64 {
		value.SetInt(202)
	}
	/* [02] ptr指向a的拷贝而不是a，所以panic*/
	defer func() {
		if err := recover(); err != nil {
			fmt.Println("出现了panic，错误信息panic为：", err)
		}
	}()

}

//(通过反射修改变量值需要要用到原变量身上才有意义)
func setValue2(x interface{}) {
	/* [01] 获取 Value 对象 */
	value := reflect.ValueOf(x)
	/* [02] 获取a的指针 */
	//Elem()方法会使返回的Value.ptr指向a的地址
	if value.Elem().Kind() == reflect.Int64 {
		value.Elem().SetInt(200)
	}

}
